home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK1.toast / Development Kits (Disc 1) / Open Transport / Sample Code / Network Watch (DMZ) 1.5 / sources / dmzOT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-01  |  26.4 KB  |  1,014 lines  |  [TEXT/MPS ]

  1. /*
  2. #-------------------------------------------------------------------------------------------
  3. #
  4. #    Program:    < DMZ 1.4 >
  5. #    File:        < dmzOT.c >
  6. #    
  7. #    by Rich Kubota
  8. #    of <Apple Macintosh Developer Technical Support - or wheverever>
  9. #
  10. #    Modification History
  11. #    6/14/94     rrk    Added OpenTransport support to DMZ
  12. #    
  13. #-------------------------------------------------------------------------------------------
  14. */
  15.  
  16. /*
  17.  *     dmz Sample OpenTransport Stuff
  18.  *
  19.  *    This unit provides OpenTansport AppleTalk support for dmz.  
  20.  *    These functions are similar to many of those provided in the dmzAT.c file.  
  21.  */
  22.  
  23. #include    "dmz.h"
  24.  
  25. // static globals here
  26. static ATSvcRef            gOTSvcRef    = nil;
  27. static MapperRef        gOTMapper    = nil;
  28. static EndpointRef        gOTEndpoint = nil;
  29. static OTNameID            gMyNameID    = 0;
  30. static UInt32            gNBPLookupOutstanding = 0;
  31. static TLookupRequest    gLookupRequest;
  32. static TLookupReply        gLookupReply;
  33.  
  34. static NBPEntity        gNBPEntity;
  35. static OTResult            gLookupResult;
  36.  
  37. static long                gNotifyFlag;
  38. static long                gStartTicks;
  39. static long                gEndTicks;
  40. static OTEventCode        gNotifyCode;
  41. static OSStatus            gNotifyErr;
  42. static void*            gOKAckMsg = NULL;
  43. static void*            gNotifyCookie;
  44. static OSStatus            gErrorAckMsg    = kOTNoError;
  45.  
  46.  
  47. /* globals from afar */
  48. /* out main dialog */
  49. extern DialogPtr         gLookupDialog;
  50. extern DialogPtr         gMyDialog;
  51. extern char             gNameGlob[34];
  52. extern SysEnvRec        GMAC;
  53. extern short            gATalkFlags;
  54.  
  55. // out of the dmzAT file
  56. extern PacketBuffer        gBuffers[kNumBuffers];    /* set up by InitEchoBuffers */
  57. extern QHdr                gFreeQ, gUsedQ;        /* set up by InitEchoBuffers */
  58. extern Handle             gSockCodeHndl;         /* handle to socket listener code resource */
  59. extern Ptr                 gBuffPtr;
  60. extern myMPPParamBlock     *gPBLkUP;
  61. extern Boolean             gUpdateListFlag;
  62. extern Boolean             gLookupFinished;
  63. extern NamesTableEntry     gMyNTE;
  64. extern AddrBlock         gTheBridgeAddress;
  65. extern Boolean            gHasPhase2;
  66.  
  67. extern Ptr                GTHEVBLPTR;
  68. extern Ptr                GTHETASKPTR;
  69.  
  70. // globals referenced from dmzLists.c
  71. extern ListHandle         gZonesList, gObjectTypeList;
  72.  
  73.  
  74. /************************* local prototypes *************************/
  75. static short    clen(char *cptr);
  76. static void        c2p(char *cptr);
  77. /********************************************************************/
  78. static OSStatus         DoBindDDPEndpoint(EndpointRef ep, DDPAddress *retAddr);
  79. static pascal void      HandleEndpointEvents(void* contextPtr, OTEventCode code,
  80.                                        OTResult result, void* it);
  81. static OSStatus          ReadData(EndpointRef ep, UInt8    *buffer, short buflen);
  82. static void                DoValueBreak(long value, const char* message);
  83.  
  84. /*
  85.  * CheckOpenTransportActive checks whether ASLM is available using
  86.  * InitLibraryManager.  If successful, then set the flag
  87.  * to indicate so
  88.  */ 
  89.  
  90. OSErr ActivateOpenTransport(void)
  91. {
  92.     OSErr        err;
  93.     OSStatus    oserr = kOTNoError;
  94.  
  95.     err = InitOpenTransport();
  96.  
  97.         // open the appletalk services provider
  98.     if (err == noErr)
  99.         gOTSvcRef = OTOpenAppleTalkServices(OTCreateConfiguration(kZIPName), 0, &oserr);
  100.     
  101.         // open an NBP Mapper service provider
  102.     if ((err == noErr) && (oserr == kOTNoError))
  103.         gOTMapper = OTOpenMapper(OTCreateConfiguration(kNBPName), 0, &oserr);
  104.         
  105.     if ((err == noErr) && (oserr == kOTNoError))
  106.     {
  107.             // install notifier for the mapper
  108.             // note that since OpenTransport sets the A5 world for a handler,
  109.             // we don't need to mess with saving/setting/restoring A5 - yea!!
  110.         oserr = OTInstallNotifier(gOTMapper, (OTNotifyProcPtr)MyDMZNBPHandler, nil);
  111.     }
  112.  
  113.         // open an endpoint ref 
  114.     if ((err == noErr) && (oserr == kOTNoError))
  115.     {
  116.         // set up the endpoint
  117.         gOTEndpoint = OTOpenEndpoint(OTCreateConfiguration(kDDPName), 0, nil, &oserr);
  118.         if (oserr == kOTNoError)
  119.         {
  120.             // install asynchronous notifier
  121.             OTInstallNotifier(gOTEndpoint, HandleEndpointEvents, &gNotifyFlag);
  122.         }
  123.     }
  124.             
  125.     if ((err == noErr) && (oserr == kOTNoError))
  126.     {                                        // if ASLM init'd ok, then the
  127.                                             // associated Open Transport libs were found
  128.         SetOTActiveFlag(gATalkFlags);    // indicate OpenTransport is active
  129.         gHasPhase2 = true;                    // we have phase 2
  130.     }
  131.     else        // error occurred somewhere
  132.     {    
  133.         if (gOTSvcRef)
  134.         {
  135.             OTCloseProvider(gOTSvcRef);
  136.             gOTSvcRef = nil;
  137.         }
  138.         if (gOTMapper)
  139.         {
  140.             OTCloseProvider(gOTMapper);
  141.             gOTMapper = nil;
  142.         }
  143.         if (gOTEndpoint)
  144.         {
  145.             OTCloseProvider(gOTEndpoint);
  146.             gOTEndpoint = nil;
  147.         }
  148.     }
  149.     
  150.     if (err != noErr)
  151.         return err;
  152.     else
  153.         return oserr;
  154. }
  155.  
  156. /*
  157.  * OpenTransportActive simplifies checking the global flag to see whether
  158.  * the OTActive flag is set.  This could also be a macro
  159.  */
  160.  
  161. Boolean OpenTransportActive(void)
  162. {
  163.     return (TstOTActiveFlag(gATalkFlags));
  164. }
  165.  
  166. /*
  167.  * GetBridgeAddressFromOT uses OpenTransport to determine whether
  168.  * there is a router on the network
  169.  */
  170.  
  171. typedef struct AppleTalkInfo AppleTalkInfo;
  172.  
  173. void GetBridgeAddressFromOT(AddrBlock *theAddr)
  174. {
  175.     AppleTalkInfo    info;
  176.     TNetbuf            reply;
  177.     OSErr            err;
  178.     
  179.         // set reply values
  180.     reply.buf = (UInt8*)&info;
  181.     reply.len = reply.maxlen = sizeof(info);
  182.     
  183.     err = OTATalkGetInfo(gOTSvcRef, &reply);
  184.     if (err != noErr)
  185.     {
  186.         DebugStr("\pError returned from OTATalkGetInfo");
  187.         theAddr->aNet = 0;
  188.         theAddr->aNode = 0;
  189.         theAddr->aSocket = 0;
  190.     }
  191.     else
  192.     {
  193.         theAddr->aNet = info.fRouterAddress.fNetwork;
  194.         theAddr->aNode = info.fRouterAddress.fNodeID;
  195.         theAddr->aSocket = info.fRouterAddress.fSocket;
  196.     }
  197. }
  198.  
  199. /*
  200.  * DoOTGetMyZone uses OpenTransport to determine what
  201.  * the current zone is
  202.  */
  203. void DoOTGetMyZone(char *myZoneBuffer)
  204. {
  205.     TNetbuf        reply;
  206.     OSErr        err;
  207.  
  208.     reply.buf = (UInt8*)myZoneBuffer;
  209.     reply.len = sizeof(Str32);
  210.     reply.maxlen = sizeof(Str32);
  211.     err = OTATalkGetMyZone(gOTSvcRef, &reply);
  212.     if (err != noErr)
  213.         myZoneBuffer[0] = 0;
  214. }
  215.  
  216. /*
  217.  * DoOTGetZoneList uses OpenTransport to determine whether
  218.  * there is a router on the network
  219.  */
  220. void DoOTGetZoneList(void)
  221. {
  222.     TNetbuf        reply;
  223.     OSErr        err = 0;
  224.     Ptr            unpackedBufferPtr, packedBufferPtr;
  225.     short        numZones;
  226.     
  227.         // need two buffers to hold the zone names
  228.         // 1 to give to the OTZoneList call to fill in a packed list of zone names
  229.         // 2 to unstuff the zones names and pass to the SetZoneCells call
  230.     packedBufferPtr = NewPtr(kMaxZoneBuffSize);     /* size of maxstring size * 255 zones */
  231.     unpackedBufferPtr = NewPtr(kMaxZoneBuffSize);     /* size of maxstring size * 255 zones */
  232.     if (packedBufferPtr != nil && unpackedBufferPtr != nil)
  233.     {
  234.         reply.buf = (UInt8*)packedBufferPtr;
  235.         reply.len = reply.maxlen = kMaxZoneBuffSize;
  236.     
  237.             // set service ref for synch mode
  238.         OTSetSynchronous(gOTSvcRef);
  239.         
  240.         err = OTATalkGetZoneList(gOTSvcRef, &reply);
  241.         
  242.         if (err != kOTNoError && err != kOTNoDataErr)
  243.             BigBadError("\pOTGetZoneList returned err - Aborting program!!");
  244.         else
  245.         {
  246.                 // unpack the zone names into the unpackedBuffer
  247.             numZones = addToOTUnpackedBuffer(packedBufferPtr, unpackedBufferPtr, reply.len);
  248.                 // set the zone names in the zone cells
  249.             SetZoneCells(unpackedBufferPtr, numZones);
  250.         }
  251.     }
  252.     else
  253.     {
  254.         BigBadError("\pError getting memory for GetZoneList call - Aborting program!!");
  255.     }
  256.     
  257.         
  258. }
  259.  
  260. void CleanupOTServices(void)
  261. {
  262.         // close AppleTalk Services
  263.     OTCloseProvider(gOTSvcRef);
  264.         // close the mapper
  265.     OTCloseProvider(gOTMapper);
  266.         // close the endpoint
  267.     OTCloseProvider(gOTEndpoint);
  268.     ClrOTLookupActiveFlag(gATalkFlags);        // clear the OTActive flag
  269. }
  270.  
  271.  
  272. /*
  273.  *    in order for us to use the standard qsort() algorithm, our data must be alligned in
  274.  *    an orderly fashion with a set offset from each data entry. This routine takes care of
  275.  *    that through simple _BlockMove manipulations.  Note that this routine is a modification
  276.  *  of the addToUnpackedBuffer routine in that it assumes that all of the names are in
  277.  *  the unpacked buffer.  Instead of the number of zones, we only know the number of
  278.  *  valid bytes in the buffer.  We also determine the number of zones and return this 
  279.  *    info to the caller.
  280.  */
  281. short addToOTUnpackedBuffer(Ptr packedBuffer, Ptr unpackedBuffer, long len)
  282. {
  283.     long    index = 0L;
  284.     short    i = 0;
  285.     
  286.     while ((index < len) && (index < kMaxZoneBuffSize - 32))
  287.     {
  288.         BlockMove((Ptr)packedBuffer+index, (Ptr)unpackedBuffer+i*33, 33L);
  289.         index += (char)((Ptr)packedBuffer+index)[0]+1L;
  290.         i++;
  291.     }
  292.     return i;
  293. }
  294.  
  295. /*******************************************************************************
  296. ** Register my name using Open Transport
  297. ********************************************************************************/
  298. void OTRegisterMyName (void)
  299. {
  300.     TRegisterRequest regreq;
  301.     TRegisterReply        regreply;
  302.     StringHandle    userNameHndl;
  303.     OSErr        err;
  304.     UInt8        nameBuf[100];
  305.     
  306.         // for registering a name, we'll first try to get the flagship name
  307.         // otherwise, we'll use the machinename
  308.     userNameHndl = GetString(kFlagshipNameResourceID);
  309.     if (**userNameHndl == 0) 
  310.     {
  311.         userNameHndl = GetString(kMachineNameResourceID); 
  312.         if(**userNameHndl == 0)
  313.         {
  314.             userNameHndl = (StringHandle)NewHandle(32);
  315.             if (userNameHndl)
  316.                 BlockMove("\pYour name here.", *userNameHndl, 15L);
  317.         }
  318.         
  319.     }
  320.         // create the NBP name string and set the len field for the string
  321.     regreq.name.len = OTMySetNBPEntity((char*)nameBuf, (Ptr)*userNameHndl, (Ptr)kEchoType, (Ptr)"\p*");
  322.     regreq.name.maxlen = sizeof(nameBuf);
  323.     regreq.name.buf = nameBuf;
  324.     
  325.         // let the system define the network address for this name
  326.     regreq.addr.len = regreq.addr.maxlen = 0;
  327.     regreq.addr.buf = NULL;
  328.     
  329.         // set up regreply
  330.     regreply.addr.maxlen = 0;
  331.     regreply.addr.buf = nil;
  332.         
  333.     OTSetSynchronous(gOTMapper);
  334.     err = OTRegisterName(gOTMapper, ®req, ®reply);
  335.     gMyNameID = regreply.nameid;
  336. }
  337.  
  338. /*******************************************************************************
  339. ** Delete my name using Open Transport
  340. ********************************************************************************/
  341. void OTDeleteMyName (void)
  342. {    
  343.     OTSetSynchronous(gOTMapper);
  344.     OTDeleteNameByID(gOTMapper, gMyNameID);    
  345. }
  346.  
  347. /*******************************************************************************
  348. ** HandleMapperEvents TMapper (NBP) Event Handling
  349. ********************************************************************************/
  350.  
  351. pascal void MyDMZNBPHandler(void* contextPtr, OTEventCode event, OTResult result, void* cookie)
  352. {
  353.  
  354.     switch (event)
  355.     {
  356.         case T_LKUPNAMERESULT:        // intermediate result notification
  357.             break;
  358.             
  359.         case T_LKUPNAMECOMPLETE:
  360.             gUpdateListFlag = true;
  361.                 // clear bit which indicates that we are doing a lookup
  362.             ClrOTLookupActiveFlag(gATalkFlags);
  363.             break;
  364.             
  365.         case T_REGNAMECOMPLETE:
  366.             if (result == kOTNoError)
  367.             {
  368.                 SetNameRegisteredFlag(gATalkFlags);
  369.                     /* if error occured registering name, there is no reason to 
  370.                      * abort the program 
  371.                      */
  372.             }
  373.             break;
  374.             
  375.         case T_DELNAMECOMPLETE:
  376.             if (result == kOTNoError)
  377.             {
  378.                 ClrNameRegisteredFlag(gATalkFlags);
  379.             }
  380.             break;
  381.             
  382.         default:
  383.             DebugStr("\pHandleMapperEvents: Unexpected Event!;g");
  384.             break;
  385.     }
  386. }
  387.  
  388. UInt16 OTMySetNBPEntity(char *buffer, Ptr nbpObject, Ptr nbpType, Ptr nbpZone)
  389. {
  390.     char*    bufPtr;
  391.     UInt16    len;
  392.     
  393.     bufPtr = buffer;
  394.  
  395.     BlockMove((Ptr)&nbpObject[1], bufPtr, nbpObject[0]);
  396.     bufPtr += nbpObject[0];        // point buffer to end of current string
  397.     len = nbpObject[0];            // collect number of chars moved to buffer
  398.  
  399.         // add the ":" character between the object and type strings
  400.     *bufPtr = ':';
  401.     bufPtr++;
  402.     len++;
  403.  
  404.     BlockMove((Ptr)&nbpType[1], bufPtr, nbpType[0]);
  405.     bufPtr += nbpType[0];        // point buffer to end of current string
  406.     len += nbpType[0];            // collect number of chars moved to buffer
  407.     
  408.         // add the "@" character between the type and zone strings
  409.     *bufPtr = '@';
  410.     bufPtr++;
  411.     len++;
  412.  
  413.     BlockMove((Ptr)&nbpZone[1], bufPtr, nbpZone[0]);
  414.     len += nbpZone[0];            // collect number of chars moved to buffer
  415.     return len;    
  416. }
  417.  
  418. void DoOTNameLookup(char *NBPObject, char *NBPType, char *NBPZone)
  419. {
  420.     OSErr    err;
  421.     
  422.         // first check to see whether a Lookup is in progress
  423.     if (TstOTLookupActiveFlag(gATalkFlags))
  424.         return;
  425.  
  426.         // set the maximum number of names to match
  427.     gLookupRequest.maxcnt = kLookupBufSize / kNBPEntityBufferSize;
  428.         // set the timeout paramter in milliseconds
  429.     gLookupRequest.timeout = 10000;
  430.         // set the name to look up
  431.  
  432.     gLookupRequest.name.len = (size_t)OTMySetNBPEntity((char*)&gNBPEntity, (Ptr)NBPObject, (Ptr)NBPType, (Ptr)NBPZone);
  433.     gLookupRequest.name.maxlen = gLookupRequest.name.len;
  434.     gLookupRequest.name.buf = (UInt8*)&gNBPEntity;
  435.     
  436.     gLookupRequest.addr.len = 0;
  437.     gLookupRequest.addr.maxlen = 0;
  438.     gLookupRequest.addr.buf = nil;
  439.     
  440.     gLookupReply.names.maxlen = kLookupBufSize;
  441.     gLookupReply.names.len = kLookupBufSize;
  442.     gLookupReply.names.buf = (UInt8*)gBuffPtr;
  443.     
  444.         // indicate that we are doing a lookup
  445.     gLookupFinished = false;
  446.         // start spinning cursor
  447.     StartAnimatedCursors(kSpinEvery5Ticks, 15);
  448.     
  449.         // make the call asynchronously
  450.     OTSetAsynchronous(gOTMapper);
  451.     err = OTLookupName(gOTMapper, &gLookupRequest, &gLookupReply);
  452.         // indicate that a lookup call is active.
  453.     SetOTLookupActiveFlag(gATalkFlags);
  454.  
  455. }
  456.  
  457. void    ProcessOTListUpdate(char *resultStr)
  458. {
  459.     Str255    errorStr;
  460.     
  461.     if (gLookupResult == noErr)
  462.     {
  463.         NumToString((long)gLookupReply.rspcount, (StringPtr)resultStr);
  464.         Pstrcat((StringPtr)resultStr, "\p items");
  465.         
  466.             // set the cells of the list
  467.         OTSetObjectTypeCells(gBuffPtr, gLookupReply.rspcount);
  468.     }
  469.     else
  470.     {
  471.         NumToString((long)gLookupResult, errorStr);
  472.         resultStr[0] = 0;
  473.         Pstrcat((StringPtr)resultStr, "\pError ID = ");
  474.         Pstrcat((StringPtr)resultStr, errorStr);
  475.     }
  476.     StopAnimatedCursors();
  477. }
  478.  
  479. void OTSetObjectTypeCells(Ptr ptr, short numDevicesGot)
  480. {
  481.     DDPNBPAddress        *theNBPAddrInfo;
  482.     NBPEntity            *nbpEntity;
  483.     Cell                 theCell;
  484.     short                 ignore;
  485.     short                 numDevicesIndex;
  486.     GrafPtr             tp;
  487.     AddrBlock             *address;
  488.     UInt32                offset;
  489.     UInt16                addrLen, nameLen, totalLen;
  490.     
  491.     unsigned char        charHolder[6];
  492.     long                g;
  493.     myNetworkEntity     myNetEnt;
  494.     Ptr                    newBuffer;
  495.     UInt8                delimiter;
  496.     char                tempStr[10];
  497.     
  498.     /* tell the user this may take a little while... */
  499.     /*waitAWhile = GetCursor(watchCursor);
  500.     SetCursor(*waitAWhile);*/
  501.     
  502.     GetPort(&tp);
  503.     SetPort(gMyDialog);
  504.  
  505.     /* make room for as many objects as we need */
  506.     newBuffer = NewPtr(numDevicesGot*sizeof(myNetworkEntity));
  507.     if(newBuffer == 0L)
  508.         return;
  509.         
  510.     LDelRow(0, 0, gObjectTypeList);    /* deletes lists's cells */
  511.     
  512.     LSetDrawingMode(false, gObjectTypeList);  /* turn drawing off */
  513.     
  514.     numDevicesIndex = 0;
  515.         
  516.     while(numDevicesIndex<numDevicesGot) {
  517.         SpinTheCursor();
  518.         theCell.v = numDevicesIndex;
  519.         
  520.         ignore = LAddRow(1, numDevicesIndex, gObjectTypeList);    
  521.  
  522.             // get the address and name lengths
  523.         addrLen = ((short*)ptr)[0];
  524.         nameLen = ((short*)ptr)[1];
  525.         
  526.             // set theAddr to point to the beginning of the DDPNBP structure
  527.         theNBPAddrInfo = (DDPNBPAddress*)(ptr + 2 * sizeof(short));
  528.         
  529.             // set address to point to the appropriate spot in the address buffer
  530.         address = (AddrBlock*)&theNBPAddrInfo->fNetwork;
  531.         
  532.         /* first move address data into "hidden" cell */
  533.         theCell.h = 1;
  534.         LSetCell((Ptr) address, 4, theCell, gObjectTypeList);
  535.         
  536.             // set the nbpEntity pointer to point to the namebuffer
  537.         nbpEntity = (NBPEntity*)&theNBPAddrInfo->fNBPNameBuffer;
  538.  
  539.         /* now move object name & type into one cell */
  540.         theCell.h = 0;
  541.         
  542.         /* object */
  543.             // extract the object name from the entity which is a nul terminated
  544.             // string with the object, type, and zone name separated by the 
  545.             // ':' and '@' characters.  Call OTExtractNBPCName which is a routine
  546.             // defined here to parse the entity up to the character specified as the
  547.             // delimiter.  The offset parameter is 0 and is passed in to indicate that
  548.             // we want to parse the object field from the beginning of the entity.
  549.         delimiter = ':';
  550.         offset = OTExtractNBPCName(nbpEntity, (char *)&myNetEnt.object, 0, &delimiter);
  551.             // the name is in c string style, convert to pascal
  552.         c2p((char *)&myNetEnt.object);
  553.             // make sure that the string length is no longer than 32 chars
  554.         if(myNetEnt.object[0] > 32)
  555.             myNetEnt.object[0] = 32;
  556.             
  557.         /* type */
  558.             // we do the same for the type string as we did for the object name
  559.             // above.
  560.         delimiter = '@';
  561.         OTExtractNBPCName(nbpEntity, (char *)&myNetEnt.type, offset, &delimiter);
  562.             // the name is in c string style, convert to pascal
  563.         c2p((char *)&myNetEnt.type);
  564.             // make sure that the string length is no longer than 32 chars
  565.         if(myNetEnt.type[0] > 32)
  566.             myNetEnt.type[0] = 32;
  567.         
  568.         /* network */
  569.         g = (long)address->aNet;
  570.         g = g & 0x0000FFFF; /* mask out hiword crap */
  571.         NumToString(g, (void *) &charHolder);
  572.         padEntry((void *) &charHolder, 5, rightJust);
  573.         BlockMove(&charHolder, &myNetEnt.net, 6L);
  574.  
  575.         /* node */
  576.         NumToString((long)address->aNode, (void *) &charHolder);
  577.         padEntry((void *) &charHolder, 3, rightJust);
  578.         BlockMove(&charHolder, &myNetEnt.node, 4L);
  579.     
  580.         /* socket */
  581.         NumToString((long)address->aSocket, (void *) &charHolder);
  582.         padEntry((void *) &charHolder, 3, rightJust);
  583.         BlockMove(&charHolder, &myNetEnt.socket, 4L);
  584.                 
  585.         BlockMove((Ptr) &myNetEnt, (Ptr)newBuffer+(numDevicesIndex)*sizeof(myNetworkEntity), 
  586.             sizeof(myNetworkEntity));
  587.  
  588.         LSetCell((Ptr)&myNetEnt, sizeof(myNetworkEntity), theCell, gObjectTypeList);    
  589.             
  590.             // increment the index counter
  591.         numDevicesIndex += 1; 
  592.             // get the total length of this NBP record
  593.         totalLen = addrLen + nameLen + 2 * sizeof(short);
  594.             // advance the ptr to the next record which is alligned on a 4 byte
  595.             // boundary
  596.         ptr = ptr + ((totalLen + 3) & ~3);
  597.             
  598.         }
  599.  
  600.     /* do a quicksort() on the mess */
  601.     letsSort(newBuffer, numDevicesGot, sizeof(myNetworkEntity));
  602.     
  603.     numDevicesIndex = 0;
  604.     
  605.     while(numDevicesIndex<numDevicesGot) {
  606.         theCell.v = numDevicesIndex;
  607.         theCell.h = 0;
  608.         BlockMove((Ptr)newBuffer+(numDevicesIndex)*sizeof(myNetworkEntity), (Ptr) &myNetEnt, sizeof(myNetworkEntity));
  609.         LSetCell((Ptr)&myNetEnt, sizeof(myNetworkEntity), theCell, gObjectTypeList);    
  610.         numDevicesIndex += 1;
  611.         }
  612.         
  613.     DisposePtr(newBuffer);
  614.     
  615.     NumToString(numDevicesIndex, (void *) tempStr);
  616.  
  617.     ParamText((ConstStr255Param)tempStr, "\p# of objects: ", "\p", "\pOT active");
  618.     
  619.     LSetDrawingMode(true, gObjectTypeList);
  620.     invalidateItem(8);
  621.     invalidateItem(2);
  622.  
  623.     SetPort(tp);
  624.     InitCursor();
  625. }
  626.  
  627. /*****************************************************************************/
  628. /* Convert a c-string to a pascal-string. */
  629. short    clen(char *cptr)
  630. {
  631.     short    i;
  632.  
  633.     for (i = 0; cptr[i]; ++i) {};
  634.     return(i);
  635. }
  636.  
  637. /*****************************************************************************/
  638. void    c2p(char *cptr)
  639. {
  640.     char    len;
  641.  
  642.     BlockMove(cptr, cptr + 1, len = clen(cptr));
  643.     *cptr = len;
  644. }
  645.  
  646. /*****************************************************************************/
  647.  
  648. /*
  649.  *    doOTEcho is the Open Transport version of the doEcho call.  It is 
  650.  *    called when the user double clicks on some item indicating
  651.  *  to send an echo packet to the echo socket on the node of that item.
  652.  *    Note that we don't use an Assembler socket listener
  653.  */
  654. void doOTEcho(myNetworkEntity    *myEnt)
  655. {
  656.     DDPAddress        retAddr, ddpAddr;
  657.     Rect            r;
  658.     TUnitData        unitdata;
  659.     Ptr                myBuffer;
  660.     long            myWaitTicks;
  661.     DialogPtr        echoDialog;
  662.     Handle            h;
  663.     GrafPtr            savedPort;
  664.     
  665.     long            tempL;
  666.     OSStatus        err = kOTNoError;
  667.     OTResult        result;
  668.  
  669.     short            itemHit;
  670.     short            kind;
  671.  
  672.     UInt8            recvBuf[ddpMaxData];
  673.     Str255            str;
  674.     char            noHopStr[2] = "\p?";
  675.     
  676. /*
  677.     the following are OTData related stuff
  678. */
  679.     OTData            otdata[3];
  680.     UInt8            buf1[64] = "\001This is a sample string to send as the first part of the buffer";
  681.                             ///123456789012345678901234567890123456789012345678901234567890123
  682.     UInt8            buf2[64] = "This is a another sample string to send as the first part buffer";
  683.  
  684.     Boolean            gotEcho = false;
  685.     Boolean            epBound = false;
  686.     Boolean            done = false;
  687.         
  688.     GetPort(&savedPort);
  689.  
  690.         // set up the ddpAddr structure of the node which we want to
  691.         // send our echo test packet to.
  692.     ddpAddr.fAddressType = AF_ATALK_DDP;
  693.     
  694.         // set the network number
  695.     StringToNum((StringPtr) myEnt->net, (long *) &tempL);
  696.     ddpAddr.fNetwork = tempL;
  697.     
  698.         // set the node number
  699.     StringToNum((StringPtr) myEnt->node, (long *) &tempL);
  700.     ddpAddr.fNodeID = tempL;
  701.     
  702.         // set the socket field to the echo socket
  703.     ddpAddr.fSocket = 4;
  704.  
  705.         // indicate that the packet is an echo DDP packet
  706.     ddpAddr.fDDPType = 4;
  707.     
  708.         // get the dialog which we use to display the results
  709.     echoDialog = GetNewDialog(131, 0L, (WindowPtr) -1L);
  710.     SetPort(echoDialog);
  711.     
  712.     TextFont(geneva);
  713.     TextSize(9);
  714.     
  715.     setupEchoDialog(echoDialog, myEnt);
  716.  
  717.         // Bind shall be handled synchronously.
  718.     OTSetSynchronous(gOTEndpoint);
  719.     
  720.         // allocate a buffer to send message
  721.     myBuffer = NewPtr(ddpMaxData);
  722.     if (myBuffer == nil)
  723.     {
  724.         GetDialogItem(echoDialog, 6, &kind, &h, &r);
  725.         SetDialogItemText(h, "\pWah… Out of mem error");
  726.         err = memFullErr;
  727.     }
  728.     else
  729.         *myBuffer = 1;                        /* tell their Echoer we want a reply with a 1 in the first byte */
  730.     
  731.     if (err == kOTNoError)
  732.     {
  733.             // get the current endpoint state
  734.         result = OTGetEndpointState(gOTEndpoint);
  735.         if (result == T_UNBND)
  736.         {
  737.                 // set up the reqAddr to point to the local echo socket
  738.             err = DoBindDDPEndpoint(gOTEndpoint, &retAddr);
  739.     
  740.             if (err != kOTNoError)
  741.             {
  742.                 GetDialogItem(echoDialog, 6, &kind, &h, &r);
  743.                 SetDialogItemText(h, "\pWah… Bind error occurred #");
  744.             }
  745.             else
  746.                 epBound = true;
  747.         }
  748.     }
  749.     
  750.     if (err == kOTNoError)
  751.     {
  752.             // send shall be handled asynchronously.
  753.         OTSetAsynchronous(gOTEndpoint);
  754.         
  755.             // set up the OTData[0] structure
  756.             otdata[0].fNext = &otdata[1];
  757.             otdata[0].fData = &buf1;
  758.             otdata[0].fLen = sizeof(buf1);
  759.             
  760.             // set up the OTData[1] structure
  761.             otdata[1].fNext = &otdata[2];
  762.             otdata[1].fData = &buf2;
  763.             otdata[1].fLen = sizeof(buf2);
  764.             
  765.             // set up the OTData[2] structure - the end of the list
  766.             otdata[2].fNext = nil;
  767.             otdata[2].fData = nil;
  768.             otdata[2].fLen = 0;
  769.             
  770.             // set up unitdata fields
  771.         unitdata.udata.buf = (UInt8*)otdata;            // data area
  772.         unitdata.udata.len = kNetbufDataIsOTData;
  773.         unitdata.addr.buf = (UInt8*)&ddpAddr;        // address area    
  774.         unitdata.addr.len = kDDPAddressLength;
  775.         unitdata.opt.len = 0;                         // no options being sent
  776.         
  777.         result = OTDontAckSends(gOTEndpoint);
  778.         gNotifyCode = 0;
  779.         
  780.         gEndTicks = 0;
  781.         gStartTicks = TickCount();            /* start the timer! */
  782.         
  783.         err = OTSndUData(gOTEndpoint, &unitdata);
  784.         StartAnimatedCursors(kSpinEvery5Ticks, 15);
  785.         
  786.         myWaitTicks = TickCount() + 300L;    /* wait 5 seconds for reply */
  787.         
  788.         result = OTDontAckSends(gOTEndpoint);
  789.         if (err != kOTNoError)
  790.         {
  791.             GetDialogItem(echoDialog, 6, &kind, &h, &r);
  792.             SetDialogItemText(h, "\pWah… Send error occurred #");
  793.         }
  794.         
  795.         if (err == kOTNoError)
  796.         {
  797.             //
  798.             // It's very important that we read the data while we are waiting for the "ack send" to complete.
  799.             // DDP can use our own message to reply to us, and if we don't "read" the message, the "ackSend"
  800.             // will never complete.
  801.             //
  802.             while ((done == false) && (myWaitTicks > TickCount()))
  803.             {
  804.                 if ( gNotifyCode == T_DATA )
  805.                 {
  806.                     gNotifyCode = 0;
  807.                      while ( ReadData(gOTEndpoint, (UInt8*)&recvBuf, ddpMaxData) != kOTNoDataErr )
  808.                     {
  809.                         OTIdle();
  810.                         SpinTheCursor();
  811.                     }
  812.                     done = true;
  813.                 }
  814.                 SpinTheCursor();
  815.                 OTIdle();
  816.             }
  817.             
  818.             if (gEndTicks != 0)
  819.             {
  820.                 GetDialogItem(echoDialog, 4, &kind, &h, &r);
  821.                 SetDialogItemText(h, (ConstStr255Param)noHopStr);
  822.  
  823.                 GetDialogItem(echoDialog, 5, &kind, &h, &r);
  824.                 NumToString(gEndTicks - gStartTicks, (void *) &str);
  825.                 SetDialogItemText(h, str);
  826.  
  827.             }
  828.             else
  829.             {
  830.                 GetDialogItem(echoDialog, 6, &kind, &h, &r);
  831.                 SetDialogItemText(h, "\pWah… no echo reply received!");
  832.             }
  833.         }
  834.     }
  835.  
  836.     StopAnimatedCursors();
  837.     if (epBound == true)
  838.     {
  839.         err = OTUnbind(gOTEndpoint);
  840.     }
  841.         
  842.     /* clean up memory allocations */
  843.     if (myBuffer != nil)
  844.         DisposePtr(myBuffer);
  845.     
  846.     /* report the results */
  847.     centerDialog((WindowPtr) echoDialog);
  848.  
  849.     InitCursor();
  850.     ShowWindow(echoDialog);
  851.     
  852.     ModalDialog(0L, &itemHit);
  853.     DisposeDialog(echoDialog);
  854.     
  855.     SetPort(savedPort);
  856. }
  857.  
  858. /*******************************************************************************
  859. ** DoBindEchoEndpoint - binds the passed endpoint ref to a DDP endpoint
  860.     the bound address is returned in the structure pointed to by the retAddr
  861.     parameter
  862. ********************************************************************************/
  863. OSStatus DoBindDDPEndpoint(EndpointRef ep, DDPAddress *retAddr)
  864. {
  865.     DDPAddress        reqAddr;
  866.     TBind            req, ret;
  867.     OSStatus        err = kOTNoError;
  868.  
  869.         // set up the reqAddr to point to the local echo socket
  870.     reqAddr.fAddressType = AF_ATALK_DDP;
  871.     reqAddr.fNetwork = 0;        // set to our network
  872.     reqAddr.fNodeID = 0;        // set to our node
  873.     reqAddr.fSocket = 0;        // bind to a dynamic socket
  874.     reqAddr.fDDPType = 0;        // accept all packets to our socket;
  875.         // bind the endpoint to the Echo socket
  876.     req.addr.buf = (UInt8*)&reqAddr;
  877.     req.addr.len = kDDPAddressLength;
  878.     req.qlen = 0;
  879.         // set up the return DDPAddress parameter if we are interested.
  880.         // in this sample, we don't use this information
  881.     ret.addr.buf = (UInt8*)retAddr;
  882.     ret.addr.maxlen = sizeof(DDPAddress);
  883.     
  884.     err = OTBind(ep, &req, &ret);
  885.     
  886.     return err;
  887.  
  888. }
  889.  
  890. /*******************************************************************************
  891. ** HandleEndpointEvents
  892. ********************************************************************************/
  893.  
  894. static pascal void  HandleEndpointEvents(void* contextPtr, OTEventCode code,
  895.                                        OTResult result, void* it)
  896. {
  897.     switch (code)
  898.     {            
  899.         case T_DATA:
  900.                 // set flag that some data has come in
  901.             gNotifyCode = code;
  902.             if ((gEndTicks == 0))
  903.             {
  904.                 gEndTicks = TickCount();
  905.             }
  906.             break;
  907.         
  908.         case T_LISTEN:
  909.         case T_CONNECT:
  910.         case T_EXDATA:
  911.         case T_DISCONNECT:
  912.         case T_ORDREL:
  913.         case T_GODATA:
  914.         case T_GOEXDATA:
  915.         case T_REQUEST:
  916.         case T_REPLY:
  917.         case T_PASSCON:
  918.         case T_RESET:
  919.         case T_MEMORYRELEASED:
  920.         case T_UNBINDCOMPLETE:
  921.                 // do nothing
  922.             break;
  923.         
  924.         
  925.         default:
  926.             DoValueBreak(code, "unknown event occurred: #");
  927.             break;
  928.     }
  929.  
  930. }
  931.  
  932. /*******************************************************************************
  933. ** ReadData
  934. ********************************************************************************/
  935.  
  936. static OSStatus ReadData(EndpointRef ep, UInt8    *buffer, short buflen)
  937. {
  938.     OTFlags            flags = 0;
  939.     DDPAddress        theDest;
  940.     TUnitData        theData;
  941.     OSStatus         err;
  942.     
  943.     theData.udata.buf    = buffer;
  944.     theData.udata.maxlen= buflen;
  945.     theData.addr.buf    = (UInt8*)&theDest;
  946.     theData.addr.maxlen    = sizeof(theDest);
  947.     theData.opt.maxlen    = 0;
  948.     
  949.     err = OTRcvUData(ep, &theData, &flags);
  950.     
  951.     if ( err != kOTNoError )
  952.         return err;
  953.             
  954.     return err;
  955. }
  956.  
  957. void DoValueBreak(long value, const char* message)
  958. {
  959.     static short    sDoErrorBreak = 0;
  960.  
  961.     {
  962.         Str255    s,
  963.                 n = "\p";
  964.  
  965.         s[0] = strlen(message);
  966.         BlockMoveData(message,&s[1],s[0]);
  967.         if (value < 0)
  968.         {
  969.             s[0] += 1;
  970.             s[s[0]] = '-';
  971.             value = -value;
  972.         }
  973.         while (value)
  974.         {
  975.             if (n[0])
  976.                 BlockMoveData(&n[1],&n[2],n[0]);
  977.             n[0]++;
  978.             n[1] = 48 + (value % 10);
  979.             value /= 10;
  980.         }
  981.         BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  982.         s[0] += n[0];
  983.  
  984.         sDoErrorBreak++;
  985.         {
  986.             short    cnt = sDoErrorBreak;
  987.  
  988.             s[0]++;
  989.             s[s[0]] = ',';
  990.             s[0]++;
  991.             s[s[0]] = ' ';
  992.             n[0] = 0;
  993.             while (cnt)
  994.             {
  995.                 if (n[0])
  996.                     BlockMoveData(&n[1],&n[2],n[0]);
  997.                 n[0]++;
  998.                 n[1] = 48 + (cnt % 10);
  999.                 cnt /= 10;
  1000.             }
  1001.             BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1002.             s[0] += n[0];
  1003.         }
  1004. #ifdef    powerpc
  1005.         SysBreakStr(s);
  1006. #else
  1007.         DebugStr(s);
  1008. #endif
  1009.     }
  1010. }
  1011.  
  1012.  
  1013.  
  1014.